import { updateNodeElement } from '../DOM'
import { createTaskQueue, arrified, createStateNode, getTag, getRoot } from '../Misc'

const taskQueue = createTaskQueue()
let subTask = null
let pendingCommit = null

const commitAllWork = fiber => {
  fiber.effects.forEach(item => {
    if (item.tag === "class_component") {
      item.stateNode.__fiber = item
    }
    if (item.effectTag === "delete") {
      item.parent.stateNode.removeChild(item.stateNode)
    } else if (item.effectTag === "update") {
      if (item.type === item.alternate.type) {
        // 节点类型相同
        updateNodeElement(item.stateNode, item, item.alternate)
      } else {
        // 节点类型不同
        item.parent.stateNode.replaceChild(item.stateNode, item.alternate.stateNode)
      }
    } else if (item.effectTag === "placement") {
      let fiber = item
      let parentFiber = item.parent
      while(parentFiber.tag === "class_component" || parentFiber.tag === "function_component") {
        parentFiber = parentFiber.parent
      }
      if (fiber.tag === "host_component") {
        parentFiber.stateNode.appendChild(fiber.stateNode)
      }
    }
  })
  // 备份旧节点
  fiber.stateNode.__rootFiberContainer = fiber
}

const getFirstTask = () => {
  // 从任务队列获取任务
  const task = taskQueue.pop()
  if (task.from === "class_component") {
    const root = getRoot(task.instance)
    task.instance.__fiber.partialState = task.partialState
    return {
      props: root.props,
      stateNode: root.stateNode, // 存储dom对象
      tag: "host_root",
      effects: [],
      child: null,
      alternate: root
    }
  }
  return {
    props: task.props,
    stateNode: task.dom, // 存储dom对象
    tag: "host_root",
    effects: [],
    child: null,
    alternate: task.dom.__rootFiberContainer
  }
}

const reconcileChildren = (fiber, children) => {
  const arrifiedChildren = arrified(children)

  let index = 0
  let numberOfElement = arrifiedChildren.length
  let element = null
  let newFiber = null
  let prevFiber = null

  let alternate = null
  if (fiber.alternate && fiber.alternate.child) {
    alternate = fiber.alternate.child
  }

  while(index < numberOfElement || alternate) {
    element = arrifiedChildren[index]
    if (!element && alternate) {
      // 删除节点
      alternate.effectTag = "delete"
      fiber.effects.push(alternate)
    } else if (element && alternate) {
      // 更新节点
      newFiber = {
        type: element.type,
        props: element.props,
        tag: getTag(element),
        effects: [],
        effectTag: "update",
        stateNode: null,
        parent: fiber,
        alternate
      }
      if (element.type === alternate.type) {
        // 类型相同
        newFiber.stateNode = alternate.stateNode
      } else {
        // 类型不同
        newFiber.stateNode = createStateNode(newFiber)
      }
    } else if (element && !alternate) {
      // 添加节点
      newFiber = {
        type: element.type,
        props: element.props,
        tag: getTag(element),
        effects: [],
        effectTag: "placement",
        stateNode: null,
        parent: fiber,
      }
      newFiber.stateNode = createStateNode(newFiber)
    }
    
    if (index === 0) {
      fiber.child = newFiber
    } else if (element) {
      prevFiber.sibling = newFiber
    }
    if (alternate && alternate.sibling) {
      alternate = alternate.sibling
    } else {
      alternate = null
    }
    prevFiber = newFiber
    index++
  }
}

const executeTask = fiber => {
  // 构建节点与节点的关系
  if (fiber.tag === "class_component") {
    if (fiber.stateNode.__fiber && fiber.stateNode.__fiber.partialState) {
      fiber.stateNode.state = {
        ...fiber.stateNode.state,
        ...fiber.stateNode.__fiber.partialState
      }
    }
    reconcileChildren(fiber, fiber.stateNode.render())
  } else if (fiber.tag === "function_component") {
    reconcileChildren(fiber, fiber.stateNode(fiber.props))
  } else {
    reconcileChildren(fiber, fiber.props.children)
  }
  if (fiber.child) {
    return fiber.child
  }
  let currentFiber = fiber
  while(currentFiber.parent) {
    currentFiber.parent.effects = currentFiber.parent.effects.concat(
      currentFiber.effects.concat([currentFiber])
    )
    if (currentFiber.sibling) {
      return currentFiber.sibling
    }
    currentFiber = currentFiber.parent
  }
  pendingCommit = currentFiber
}

const workLoop = deadline => {
  if (!subTask) {
    subTask = getFirstTask()
  }
  while(subTask && deadline.timeRemaining() > 1) {
    subTask = executeTask(subTask)
  }
  if (pendingCommit) {
    commitAllWork(pendingCommit)
  }
}

const performTask = deadline => {
  workLoop(deadline)
  if (subTask || !taskQueue.isEmpty) {
    window.requestIdleCallback(performTask)
  }
}

export function render(element, dom) {
  // 像任务队列添加任务
  // 任务就是通过vdom创建fiber对象

  taskQueue.push({
    dom,
    props: {children: element}
  })
  
  // 浏览器空余时间调用任务
  window.requestIdleCallback(performTask)
}

export function scheduleUpdate(instance, partialState) {
  taskQueue.push({
    from: "class_component",
    instance,
    partialState
  })
  // 浏览器空余时间调用任务
  window.requestIdleCallback(performTask)
}